1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.builder;
18  
19  import java.lang.reflect.AccessibleObject;
20  import java.lang.reflect.Field;
21  import java.lang.reflect.Modifier;
22  import java.util.Collection;
23  import java.util.HashSet;
24  import java.util.Set;
25  
26  import org.apache.commons.lang3.ArrayUtils;
27  import org.apache.commons.lang3.tuple.Pair;
28  
29  /**
30   * <p>Assists in implementing {@link Object#equals(Object)} methods.</p>
31   *
32   * <p> This class provides methods to build a good equals method for any
33   * class. It follows rules laid out in
34   * <a href="http://www.oracle.com/technetwork/java/effectivejava-136174.html">Effective Java</a>
35   * , by Joshua Bloch. In particular the rule for comparing <code>doubles</code>,
36   * <code>floats</code>, and arrays can be tricky. Also, making sure that
37   * <code>equals()</code> and <code>hashCode()</code> are consistent can be
38   * difficult.</p>
39   *
40   * <p>Two Objects that compare as equals must generate the same hash code,
41   * but two Objects with the same hash code do not have to be equal.</p>
42   *
43   * <p>All relevant fields should be included in the calculation of equals.
44   * Derived fields may be ignored. In particular, any field used in
45   * generating a hash code must be used in the equals method, and vice
46   * versa.</p>
47   *
48   * <p>Typical use for the code is as follows:</p>
49   * <pre>
50   * public boolean equals(Object obj) {
51   *   if (obj == null) { return false; }
52   *   if (obj == this) { return true; }
53   *   if (obj.getClass() != getClass()) {
54   *     return false;
55   *   }
56   *   MyClass rhs = (MyClass) obj;
57   *   return new EqualsBuilder()
58   *                 .appendSuper(super.equals(obj))
59   *                 .append(field1, rhs.field1)
60   *                 .append(field2, rhs.field2)
61   *                 .append(field3, rhs.field3)
62   *                 .isEquals();
63   *  }
64   * </pre>
65   *
66   * <p> Alternatively, there is a method that uses reflection to determine
67   * the fields to test. Because these fields are usually private, the method,
68   * <code>reflectionEquals</code>, uses <code>AccessibleObject.setAccessible</code> to
69   * change the visibility of the fields. This will fail under a security
70   * manager, unless the appropriate permissions are set up correctly. It is
71   * also slower than testing explicitly.  Non-primitive fields are compared using 
72   * <code>equals()</code>.</p>
73   *
74   * <p> A typical invocation for this method would look like:</p>
75   * <pre>
76   * public boolean equals(Object obj) {
77   *   return EqualsBuilder.reflectionEquals(this, obj);
78   * }
79   * </pre>
80   *
81   * @since 1.0
82   * @version $Id$
83   */
84  public class EqualsBuilder implements Builder<Boolean> {
85  
86      /**
87       * <p>
88       * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
89       * </p>
90       *
91       * @since 3.0
92       */
93      private static final ThreadLocal<Set<Pair<IDKey, IDKey>>> REGISTRY = new ThreadLocal<Set<Pair<IDKey, IDKey>>>();
94  
95      /*
96       * NOTE: we cannot store the actual objects in a HashSet, as that would use the very hashCode()
97       * we are in the process of calculating.
98       *
99       * So we generate a one-to-one mapping from the original object to a new object.
100      *
101      * Now HashSet uses equals() to determine if two elements with the same hashcode really
102      * are equal, so we also need to ensure that the replacement objects are only equal
103      * if the original objects are identical.
104      *
105      * The original implementation (2.4 and before) used the System.indentityHashCode()
106      * method - however this is not guaranteed to generate unique ids (e.g. LANG-459)
107      *
108      * We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey)
109      * to disambiguate the duplicate ids.
110      */
111 
112     /**
113      * <p>
114      * Returns the registry of object pairs being traversed by the reflection
115      * methods in the current thread.
116      * </p>
117      *
118      * @return Set the registry of objects being traversed
119      * @since 3.0
120      */
121     static Set<Pair<IDKey, IDKey>> getRegistry() {
122         return REGISTRY.get();
123     }
124 
125     /**
126      * <p>
127      * Converters value pair into a register pair.
128      * </p>
129      *
130      * @param lhs <code>this</code> object
131      * @param rhs the other object
132      *
133      * @return the pair
134      */
135     static Pair<IDKey, IDKey> getRegisterPair(final Object lhs, final Object rhs) {
136         final IDKey left = new IDKey(lhs);
137         final IDKey right = new IDKey(rhs);
138         return Pair.of(left, right);
139     }
140 
141     /**
142      * <p>
143      * Returns <code>true</code> if the registry contains the given object pair.
144      * Used by the reflection methods to avoid infinite loops.
145      * Objects might be swapped therefore a check is needed if the object pair
146      * is registered in given or swapped order.
147      * </p>
148      *
149      * @param lhs <code>this</code> object to lookup in registry
150      * @param rhs the other object to lookup on registry
151      * @return boolean <code>true</code> if the registry contains the given object.
152      * @since 3.0
153      */
154     static boolean isRegistered(final Object lhs, final Object rhs) {
155         final Set<Pair<IDKey, IDKey>> registry = getRegistry();
156         final Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
157         final Pair<IDKey, IDKey> swappedPair = Pair.of(pair.getLeft(), pair.getRight());
158 
159         return registry != null
160                 && (registry.contains(pair) || registry.contains(swappedPair));
161     }
162 
163     /**
164      * <p>
165      * Registers the given object pair.
166      * Used by the reflection methods to avoid infinite loops.
167      * </p>
168      *
169      * @param lhs <code>this</code> object to register
170      * @param rhs the other object to register
171      */
172     static void register(final Object lhs, final Object rhs) {
173         synchronized (EqualsBuilder.class) {
174             if (getRegistry() == null) {
175                 REGISTRY.set(new HashSet<Pair<IDKey, IDKey>>());
176             }
177         }
178 
179         final Set<Pair<IDKey, IDKey>> registry = getRegistry();
180         final Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
181         registry.add(pair);
182     }
183 
184     /**
185      * <p>
186      * Unregisters the given object pair.
187      * </p>
188      *
189      * <p>
190      * Used by the reflection methods to avoid infinite loops.
191      *
192      * @param lhs <code>this</code> object to unregister
193      * @param rhs the other object to unregister
194      * @since 3.0
195      */
196     static void unregister(final Object lhs, final Object rhs) {
197         Set<Pair<IDKey, IDKey>> registry = getRegistry();
198         if (registry != null) {
199             final Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
200             registry.remove(pair);
201             synchronized (EqualsBuilder.class) {
202                 //read again
203                 registry = getRegistry();
204                 if (registry != null && registry.isEmpty()) {
205                     REGISTRY.remove();
206                 }
207             }
208         }
209     }
210 
211     /**
212      * If the fields tested are equals.
213      * The default value is <code>true</code>.
214      */
215     private boolean isEquals = true;
216 
217     /**
218      * <p>Constructor for EqualsBuilder.</p>
219      *
220      * <p>Starts off assuming that equals is <code>true</code>.</p>
221      * @see Object#equals(Object)
222      */
223     public EqualsBuilder() {
224         // do nothing for now.
225     }
226 
227     //-------------------------------------------------------------------------
228 
229     /**
230      * <p>This method uses reflection to determine if the two <code>Object</code>s
231      * are equal.</p>
232      *
233      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
234      * fields. This means that it will throw a security exception if run under
235      * a security manager, if the permissions are not set up correctly. It is also
236      * not as efficient as testing explicitly. Non-primitive fields are compared using 
237      * <code>equals()</code>.</p>
238      * 
239      * <p>Transient members will be not be tested, as they are likely derived
240      * fields, and not part of the value of the Object.</p>
241      *
242      * <p>Static fields will not be tested. Superclass fields will be included.</p>
243      *
244      * @param lhs  <code>this</code> object
245      * @param rhs  the other object
246      * @param excludeFields  Collection of String field names to exclude from testing
247      * @return <code>true</code> if the two Objects have tested equals.
248      */
249     public static boolean reflectionEquals(final Object lhs, final Object rhs, final Collection<String> excludeFields) {
250         return reflectionEquals(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
251     }
252 
253     /**
254      * <p>This method uses reflection to determine if the two <code>Object</code>s
255      * are equal.</p>
256      *
257      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
258      * fields. This means that it will throw a security exception if run under
259      * a security manager, if the permissions are not set up correctly. It is also
260      * not as efficient as testing explicitly. Non-primitive fields are compared using 
261      * <code>equals()</code>.</p>
262      *
263      * <p>Transient members will be not be tested, as they are likely derived
264      * fields, and not part of the value of the Object.</p>
265      *
266      * <p>Static fields will not be tested. Superclass fields will be included.</p>
267      *
268      * @param lhs  <code>this</code> object
269      * @param rhs  the other object
270      * @param excludeFields  array of field names to exclude from testing
271      * @return <code>true</code> if the two Objects have tested equals.
272      */
273     public static boolean reflectionEquals(final Object lhs, final Object rhs, final String... excludeFields) {
274         return reflectionEquals(lhs, rhs, false, null, excludeFields);
275     }
276 
277     /**
278      * <p>This method uses reflection to determine if the two <code>Object</code>s
279      * are equal.</p>
280      *
281      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
282      * fields. This means that it will throw a security exception if run under
283      * a security manager, if the permissions are not set up correctly. It is also
284      * not as efficient as testing explicitly. Non-primitive fields are compared using 
285      * <code>equals()</code>.</p>
286      *
287      * <p>If the TestTransients parameter is set to <code>true</code>, transient
288      * members will be tested, otherwise they are ignored, as they are likely
289      * derived fields, and not part of the value of the <code>Object</code>.</p>
290      *
291      * <p>Static fields will not be tested. Superclass fields will be included.</p>
292      *
293      * @param lhs  <code>this</code> object
294      * @param rhs  the other object
295      * @param testTransients  whether to include transient fields
296      * @return <code>true</code> if the two Objects have tested equals.
297      */
298     public static boolean reflectionEquals(final Object lhs, final Object rhs, final boolean testTransients) {
299         return reflectionEquals(lhs, rhs, testTransients, null);
300     }
301 
302     /**
303      * <p>This method uses reflection to determine if the two <code>Object</code>s
304      * are equal.</p>
305      *
306      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
307      * fields. This means that it will throw a security exception if run under
308      * a security manager, if the permissions are not set up correctly. It is also
309      * not as efficient as testing explicitly. Non-primitive fields are compared using 
310      * <code>equals()</code>.</p>
311      *
312      * <p>If the testTransients parameter is set to <code>true</code>, transient
313      * members will be tested, otherwise they are ignored, as they are likely
314      * derived fields, and not part of the value of the <code>Object</code>.</p>
315      *
316      * <p>Static fields will not be included. Superclass fields will be appended
317      * up to and including the specified superclass. A null superclass is treated
318      * as java.lang.Object.</p>
319      *
320      * @param lhs  <code>this</code> object
321      * @param rhs  the other object
322      * @param testTransients  whether to include transient fields
323      * @param reflectUpToClass  the superclass to reflect up to (inclusive),
324      *  may be <code>null</code>
325      * @param excludeFields  array of field names to exclude from testing
326      * @return <code>true</code> if the two Objects have tested equals.
327      * @since 2.0
328      */
329     public static boolean reflectionEquals(final Object lhs, final Object rhs, final boolean testTransients, final Class<?> reflectUpToClass,
330             final String... excludeFields) {
331         if (lhs == rhs) {
332             return true;
333         }
334         if (lhs == null || rhs == null) {
335             return false;
336         }
337         // Find the leaf class since there may be transients in the leaf
338         // class or in classes between the leaf and root.
339         // If we are not testing transients or a subclass has no ivars,
340         // then a subclass can test equals to a superclass.
341         final Class<?> lhsClass = lhs.getClass();
342         final Class<?> rhsClass = rhs.getClass();
343         Class<?> testClass;
344         if (lhsClass.isInstance(rhs)) {
345             testClass = lhsClass;
346             if (!rhsClass.isInstance(lhs)) {
347                 // rhsClass is a subclass of lhsClass
348                 testClass = rhsClass;
349             }
350         } else if (rhsClass.isInstance(lhs)) {
351             testClass = rhsClass;
352             if (!lhsClass.isInstance(rhs)) {
353                 // lhsClass is a subclass of rhsClass
354                 testClass = lhsClass;
355             }
356         } else {
357             // The two classes are not related.
358             return false;
359         }
360         final EqualsBuilder equalsBuilder = new EqualsBuilder();
361         try {
362             if (testClass.isArray()) {
363                 equalsBuilder.append(lhs, rhs);
364             } else {
365                 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
366                 while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
367                     testClass = testClass.getSuperclass();
368                     reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
369                 }
370             }
371         } catch (final IllegalArgumentException e) {
372             // In this case, we tried to test a subclass vs. a superclass and
373             // the subclass has ivars or the ivars are transient and
374             // we are testing transients.
375             // If a subclass has ivars that we are trying to test them, we get an
376             // exception and we know that the objects are not equal.
377             return false;
378         }
379         return equalsBuilder.isEquals();
380     }
381 
382     /**
383      * <p>Appends the fields and values defined by the given object of the
384      * given Class.</p>
385      *
386      * @param lhs  the left hand object
387      * @param rhs  the right hand object
388      * @param clazz  the class to append details of
389      * @param builder  the builder to append to
390      * @param useTransients  whether to test transient fields
391      * @param excludeFields  array of field names to exclude from testing
392      */
393     private static void reflectionAppend(
394         final Object lhs,
395         final Object rhs,
396         final Class<?> clazz,
397         final EqualsBuilder builder,
398         final boolean useTransients,
399         final String[] excludeFields) {
400 
401         if (isRegistered(lhs, rhs)) {
402             return;
403         }
404 
405         try {
406             register(lhs, rhs);
407             final Field[] fields = clazz.getDeclaredFields();
408             AccessibleObject.setAccessible(fields, true);
409             for (int i = 0; i < fields.length && builder.isEquals; i++) {
410                 final Field f = fields[i];
411                 if (!ArrayUtils.contains(excludeFields, f.getName())
412                     && (f.getName().indexOf('$') == -1)
413                     && (useTransients || !Modifier.isTransient(f.getModifiers()))
414                     && (!Modifier.isStatic(f.getModifiers()))) {
415                     try {
416                         builder.append(f.get(lhs), f.get(rhs));
417                     } catch (final IllegalAccessException e) {
418                         //this can't happen. Would get a Security exception instead
419                         //throw a runtime exception in case the impossible happens.
420                         throw new InternalError("Unexpected IllegalAccessException");
421                     }
422                 }
423             }
424         } finally {
425             unregister(lhs, rhs);
426         }
427     }
428 
429     //-------------------------------------------------------------------------
430 
431     /**
432      * <p>Adds the result of <code>super.equals()</code> to this builder.</p>
433      *
434      * @param superEquals  the result of calling <code>super.equals()</code>
435      * @return EqualsBuilder - used to chain calls.
436      * @since 2.0
437      */
438     public EqualsBuilder appendSuper(final boolean superEquals) {
439         if (isEquals == false) {
440             return this;
441         }
442         isEquals = superEquals;
443         return this;
444     }
445 
446     //-------------------------------------------------------------------------
447 
448     /**
449      * <p>Test if two <code>Object</code>s are equal using their
450      * <code>equals</code> method.</p>
451      *
452      * @param lhs  the left hand object
453      * @param rhs  the right hand object
454      * @return EqualsBuilder - used to chain calls.
455      */
456     public EqualsBuilder append(final Object lhs, final Object rhs) {
457         if (isEquals == false) {
458             return this;
459         }
460         if (lhs == rhs) {
461             return this;
462         }
463         if (lhs == null || rhs == null) {
464             this.setEquals(false);
465             return this;
466         }
467         final Class<?> lhsClass = lhs.getClass();
468         if (!lhsClass.isArray()) {
469             // The simple case, not an array, just test the element
470             isEquals = lhs.equals(rhs);
471         } else if (lhs.getClass() != rhs.getClass()) {
472             // Here when we compare different dimensions, for example: a boolean[][] to a boolean[]
473             this.setEquals(false);
474         }
475         // 'Switch' on type of array, to dispatch to the correct handler
476         // This handles multi dimensional arrays of the same depth
477         else if (lhs instanceof long[]) {
478             append((long[]) lhs, (long[]) rhs);
479         } else if (lhs instanceof int[]) {
480             append((int[]) lhs, (int[]) rhs);
481         } else if (lhs instanceof short[]) {
482             append((short[]) lhs, (short[]) rhs);
483         } else if (lhs instanceof char[]) {
484             append((char[]) lhs, (char[]) rhs);
485         } else if (lhs instanceof byte[]) {
486             append((byte[]) lhs, (byte[]) rhs);
487         } else if (lhs instanceof double[]) {
488             append((double[]) lhs, (double[]) rhs);
489         } else if (lhs instanceof float[]) {
490             append((float[]) lhs, (float[]) rhs);
491         } else if (lhs instanceof boolean[]) {
492             append((boolean[]) lhs, (boolean[]) rhs);
493         } else {
494             // Not an array of primitives
495             append((Object[]) lhs, (Object[]) rhs);
496         }
497         return this;
498     }
499 
500     /**
501      * <p>
502      * Test if two <code>long</code> s are equal.
503      * </p>
504      *
505      * @param lhs
506      *                  the left hand <code>long</code>
507      * @param rhs
508      *                  the right hand <code>long</code>
509      * @return EqualsBuilder - used to chain calls.
510      */
511     public EqualsBuilder append(final long lhs, final long rhs) {
512         if (isEquals == false) {
513             return this;
514         }
515         isEquals = (lhs == rhs);
516         return this;
517     }
518 
519     /**
520      * <p>Test if two <code>int</code>s are equal.</p>
521      *
522      * @param lhs  the left hand <code>int</code>
523      * @param rhs  the right hand <code>int</code>
524      * @return EqualsBuilder - used to chain calls.
525      */
526     public EqualsBuilder append(final int lhs, final int rhs) {
527         if (isEquals == false) {
528             return this;
529         }
530         isEquals = (lhs == rhs);
531         return this;
532     }
533 
534     /**
535      * <p>Test if two <code>short</code>s are equal.</p>
536      *
537      * @param lhs  the left hand <code>short</code>
538      * @param rhs  the right hand <code>short</code>
539      * @return EqualsBuilder - used to chain calls.
540      */
541     public EqualsBuilder append(final short lhs, final short rhs) {
542         if (isEquals == false) {
543             return this;
544         }
545         isEquals = (lhs == rhs);
546         return this;
547     }
548 
549     /**
550      * <p>Test if two <code>char</code>s are equal.</p>
551      *
552      * @param lhs  the left hand <code>char</code>
553      * @param rhs  the right hand <code>char</code>
554      * @return EqualsBuilder - used to chain calls.
555      */
556     public EqualsBuilder append(final char lhs, final char rhs) {
557         if (isEquals == false) {
558             return this;
559         }
560         isEquals = (lhs == rhs);
561         return this;
562     }
563 
564     /**
565      * <p>Test if two <code>byte</code>s are equal.</p>
566      *
567      * @param lhs  the left hand <code>byte</code>
568      * @param rhs  the right hand <code>byte</code>
569      * @return EqualsBuilder - used to chain calls.
570      */
571     public EqualsBuilder append(final byte lhs, final byte rhs) {
572         if (isEquals == false) {
573             return this;
574         }
575         isEquals = (lhs == rhs);
576         return this;
577     }
578 
579     /**
580      * <p>Test if two <code>double</code>s are equal by testing that the
581      * pattern of bits returned by <code>doubleToLong</code> are equal.</p>
582      *
583      * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
584      *
585      * <p>It is compatible with the hash code generated by
586      * <code>HashCodeBuilder</code>.</p>
587      *
588      * @param lhs  the left hand <code>double</code>
589      * @param rhs  the right hand <code>double</code>
590      * @return EqualsBuilder - used to chain calls.
591      */
592     public EqualsBuilder append(final double lhs, final double rhs) {
593         if (isEquals == false) {
594             return this;
595         }
596         return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
597     }
598 
599     /**
600      * <p>Test if two <code>float</code>s are equal byt testing that the
601      * pattern of bits returned by doubleToLong are equal.</p>
602      *
603      * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
604      *
605      * <p>It is compatible with the hash code generated by
606      * <code>HashCodeBuilder</code>.</p>
607      *
608      * @param lhs  the left hand <code>float</code>
609      * @param rhs  the right hand <code>float</code>
610      * @return EqualsBuilder - used to chain calls.
611      */
612     public EqualsBuilder append(final float lhs, final float rhs) {
613         if (isEquals == false) {
614             return this;
615         }
616         return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
617     }
618 
619     /**
620      * <p>Test if two <code>booleans</code>s are equal.</p>
621      *
622      * @param lhs  the left hand <code>boolean</code>
623      * @param rhs  the right hand <code>boolean</code>
624      * @return EqualsBuilder - used to chain calls.
625       */
626     public EqualsBuilder append(final boolean lhs, final boolean rhs) {
627         if (isEquals == false) {
628             return this;
629         }
630         isEquals = (lhs == rhs);
631         return this;
632     }
633 
634     /**
635      * <p>Performs a deep comparison of two <code>Object</code> arrays.</p>
636      *
637      * <p>This also will be called for the top level of
638      * multi-dimensional, ragged, and multi-typed arrays.</p>
639      *
640      * @param lhs  the left hand <code>Object[]</code>
641      * @param rhs  the right hand <code>Object[]</code>
642      * @return EqualsBuilder - used to chain calls.
643      */
644     public EqualsBuilder append(final Object[] lhs, final Object[] rhs) {
645         if (isEquals == false) {
646             return this;
647         }
648         if (lhs == rhs) {
649             return this;
650         }
651         if (lhs == null || rhs == null) {
652             this.setEquals(false);
653             return this;
654         }
655         if (lhs.length != rhs.length) {
656             this.setEquals(false);
657             return this;
658         }
659         for (int i = 0; i < lhs.length && isEquals; ++i) {
660             append(lhs[i], rhs[i]);
661         }
662         return this;
663     }
664 
665     /**
666      * <p>Deep comparison of array of <code>long</code>. Length and all
667      * values are compared.</p>
668      *
669      * <p>The method {@link #append(long, long)} is used.</p>
670      *
671      * @param lhs  the left hand <code>long[]</code>
672      * @param rhs  the right hand <code>long[]</code>
673      * @return EqualsBuilder - used to chain calls.
674      */
675     public EqualsBuilder append(final long[] lhs, final long[] rhs) {
676         if (isEquals == false) {
677             return this;
678         }
679         if (lhs == rhs) {
680             return this;
681         }
682         if (lhs == null || rhs == null) {
683             this.setEquals(false);
684             return this;
685         }
686         if (lhs.length != rhs.length) {
687             this.setEquals(false);
688             return this;
689         }
690         for (int i = 0; i < lhs.length && isEquals; ++i) {
691             append(lhs[i], rhs[i]);
692         }
693         return this;
694     }
695 
696     /**
697      * <p>Deep comparison of array of <code>int</code>. Length and all
698      * values are compared.</p>
699      *
700      * <p>The method {@link #append(int, int)} is used.</p>
701      *
702      * @param lhs  the left hand <code>int[]</code>
703      * @param rhs  the right hand <code>int[]</code>
704      * @return EqualsBuilder - used to chain calls.
705      */
706     public EqualsBuilder append(final int[] lhs, final int[] rhs) {
707         if (isEquals == false) {
708             return this;
709         }
710         if (lhs == rhs) {
711             return this;
712         }
713         if (lhs == null || rhs == null) {
714             this.setEquals(false);
715             return this;
716         }
717         if (lhs.length != rhs.length) {
718             this.setEquals(false);
719             return this;
720         }
721         for (int i = 0; i < lhs.length && isEquals; ++i) {
722             append(lhs[i], rhs[i]);
723         }
724         return this;
725     }
726 
727     /**
728      * <p>Deep comparison of array of <code>short</code>. Length and all
729      * values are compared.</p>
730      *
731      * <p>The method {@link #append(short, short)} is used.</p>
732      *
733      * @param lhs  the left hand <code>short[]</code>
734      * @param rhs  the right hand <code>short[]</code>
735      * @return EqualsBuilder - used to chain calls.
736      */
737     public EqualsBuilder append(final short[] lhs, final short[] rhs) {
738         if (isEquals == false) {
739             return this;
740         }
741         if (lhs == rhs) {
742             return this;
743         }
744         if (lhs == null || rhs == null) {
745             this.setEquals(false);
746             return this;
747         }
748         if (lhs.length != rhs.length) {
749             this.setEquals(false);
750             return this;
751         }
752         for (int i = 0; i < lhs.length && isEquals; ++i) {
753             append(lhs[i], rhs[i]);
754         }
755         return this;
756     }
757 
758     /**
759      * <p>Deep comparison of array of <code>char</code>. Length and all
760      * values are compared.</p>
761      *
762      * <p>The method {@link #append(char, char)} is used.</p>
763      *
764      * @param lhs  the left hand <code>char[]</code>
765      * @param rhs  the right hand <code>char[]</code>
766      * @return EqualsBuilder - used to chain calls.
767      */
768     public EqualsBuilder append(final char[] lhs, final char[] rhs) {
769         if (isEquals == false) {
770             return this;
771         }
772         if (lhs == rhs) {
773             return this;
774         }
775         if (lhs == null || rhs == null) {
776             this.setEquals(false);
777             return this;
778         }
779         if (lhs.length != rhs.length) {
780             this.setEquals(false);
781             return this;
782         }
783         for (int i = 0; i < lhs.length && isEquals; ++i) {
784             append(lhs[i], rhs[i]);
785         }
786         return this;
787     }
788 
789     /**
790      * <p>Deep comparison of array of <code>byte</code>. Length and all
791      * values are compared.</p>
792      *
793      * <p>The method {@link #append(byte, byte)} is used.</p>
794      *
795      * @param lhs  the left hand <code>byte[]</code>
796      * @param rhs  the right hand <code>byte[]</code>
797      * @return EqualsBuilder - used to chain calls.
798      */
799     public EqualsBuilder append(final byte[] lhs, final byte[] rhs) {
800         if (isEquals == false) {
801             return this;
802         }
803         if (lhs == rhs) {
804             return this;
805         }
806         if (lhs == null || rhs == null) {
807             this.setEquals(false);
808             return this;
809         }
810         if (lhs.length != rhs.length) {
811             this.setEquals(false);
812             return this;
813         }
814         for (int i = 0; i < lhs.length && isEquals; ++i) {
815             append(lhs[i], rhs[i]);
816         }
817         return this;
818     }
819 
820     /**
821      * <p>Deep comparison of array of <code>double</code>. Length and all
822      * values are compared.</p>
823      *
824      * <p>The method {@link #append(double, double)} is used.</p>
825      *
826      * @param lhs  the left hand <code>double[]</code>
827      * @param rhs  the right hand <code>double[]</code>
828      * @return EqualsBuilder - used to chain calls.
829      */
830     public EqualsBuilder append(final double[] lhs, final double[] rhs) {
831         if (isEquals == false) {
832             return this;
833         }
834         if (lhs == rhs) {
835             return this;
836         }
837         if (lhs == null || rhs == null) {
838             this.setEquals(false);
839             return this;
840         }
841         if (lhs.length != rhs.length) {
842             this.setEquals(false);
843             return this;
844         }
845         for (int i = 0; i < lhs.length && isEquals; ++i) {
846             append(lhs[i], rhs[i]);
847         }
848         return this;
849     }
850 
851     /**
852      * <p>Deep comparison of array of <code>float</code>. Length and all
853      * values are compared.</p>
854      *
855      * <p>The method {@link #append(float, float)} is used.</p>
856      *
857      * @param lhs  the left hand <code>float[]</code>
858      * @param rhs  the right hand <code>float[]</code>
859      * @return EqualsBuilder - used to chain calls.
860      */
861     public EqualsBuilder append(final float[] lhs, final float[] rhs) {
862         if (isEquals == false) {
863             return this;
864         }
865         if (lhs == rhs) {
866             return this;
867         }
868         if (lhs == null || rhs == null) {
869             this.setEquals(false);
870             return this;
871         }
872         if (lhs.length != rhs.length) {
873             this.setEquals(false);
874             return this;
875         }
876         for (int i = 0; i < lhs.length && isEquals; ++i) {
877             append(lhs[i], rhs[i]);
878         }
879         return this;
880     }
881 
882     /**
883      * <p>Deep comparison of array of <code>boolean</code>. Length and all
884      * values are compared.</p>
885      *
886      * <p>The method {@link #append(boolean, boolean)} is used.</p>
887      *
888      * @param lhs  the left hand <code>boolean[]</code>
889      * @param rhs  the right hand <code>boolean[]</code>
890      * @return EqualsBuilder - used to chain calls.
891      */
892     public EqualsBuilder append(final boolean[] lhs, final boolean[] rhs) {
893         if (isEquals == false) {
894             return this;
895         }
896         if (lhs == rhs) {
897             return this;
898         }
899         if (lhs == null || rhs == null) {
900             this.setEquals(false);
901             return this;
902         }
903         if (lhs.length != rhs.length) {
904             this.setEquals(false);
905             return this;
906         }
907         for (int i = 0; i < lhs.length && isEquals; ++i) {
908             append(lhs[i], rhs[i]);
909         }
910         return this;
911     }
912 
913     /**
914      * <p>Returns <code>true</code> if the fields that have been checked
915      * are all equal.</p>
916      *
917      * @return boolean
918      */
919     public boolean isEquals() {
920         return this.isEquals;
921     }
922 
923     /**
924      * <p>Returns <code>true</code> if the fields that have been checked
925      * are all equal.</p>
926      *
927      * @return <code>true</code> if all of the fields that have been checked
928      *         are equal, <code>false</code> otherwise.
929      *
930      * @since 3.0
931      */
932     @Override
933     public Boolean build() {
934         return Boolean.valueOf(isEquals());
935     }
936 
937     /**
938      * Sets the <code>isEquals</code> value.
939      *
940      * @param isEquals The value to set.
941      * @since 2.1
942      */
943     protected void setEquals(final boolean isEquals) {
944         this.isEquals = isEquals;
945     }
946 
947     /**
948      * Reset the EqualsBuilder so you can use the same object again
949      * @since 2.5
950      */
951     public void reset() {
952         this.isEquals = true;
953     }
954 }